package util

import (
	"fmt"
	"sync"
	"time"
)

// FrequencyRecord 记录key历次出现的时间，从而得到频率
type FrequencyRecord struct {
	keyTime  map[string][]int64 // key和存储历次出现时间切片的映射
	duration int64              // 时间段长度
	times    int                // 在该时间段内每个key允许出现的频次
	syncLock sync.Mutex         // map读写均需要加锁，每一个结构体对象对应一个map，对应一个锁对象
}

// Add 增加key的出现记录
func (f *FrequencyRecord) Add(key string) {
	f.syncLock.Lock()
	defer f.syncLock.Unlock()
	f.keyTime[key] = append(f.keyTime[key], time.Now().UnixMilli())
}

// clear 清除过于悠久的记录
func (f *FrequencyRecord) clear(key string) {
	f.syncLock.Lock()
	defer f.syncLock.Unlock()
	l := len(f.keyTime[key])
	idx := l - 1
	if l == 0 {
		return
	}
	for i, val := range f.keyTime[key] {
		if val+f.duration >= f.keyTime[key][l-1] {
			idx = i
			break
		}
	}
	f.keyTime[key] = f.keyTime[key][idx:]
}

// Check 检查是否过于频繁
func (f *FrequencyRecord) Check(key string) bool {
	f.clear(key)
	// 注意不要在调用clear部分加锁，否则会造成死锁
	f.syncLock.Lock()
	defer f.syncLock.Unlock()
	if len(f.keyTime[key]) <= f.times {
		return false
	} else {
		return true
	}
}

// Show 打印对象的信息，调试用
func (f *FrequencyRecord) Show() {
	f.syncLock.Lock()
	defer f.syncLock.Unlock()
	fmt.Println(f.keyTime)
}

var testUtil = &FrequencyRecord{
	keyTime:  make(map[string][]int64),
	duration: 400,
	times:    5,
}
var IpFrequencyRecord = &FrequencyRecord{
	keyTime:  make(map[string][]int64),
	duration: 1000 * 10, // 十秒钟允许二十次请求
	times:    20,
}
var AccountFrequencyRecord = &FrequencyRecord{
	keyTime:  make(map[string][]int64),
	duration: 1000 * 10, // 十秒钟允许十次请求
	times:    10,
}

func Test() {
	for i := 0; i < 1000; i++ {
		go testUtil.Add("zhang")
		go testUtil.Add("li")
		go testUtil.Check("zhang")
	}
	testUtil.Show()
}
